#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <mysql/mysql.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>

#include "../inc/tcp.h"
#include "../inc/register.h"
#include "../inc/cJSON.h"
#include "../inc/agreement.h"

// 提前声明静态函数
static int mysql_query_ex(MYSQL *conn, const char *sql, MYSQL_RES **res);
static int query_user_online_connfd(MYSQL *db_conn, int user_id, int *out_connfd);
static int get_userid_by_userid(MYSQL *db_conn, int user_id, char *out_userid, size_t out_len);

// 处理好友申请操作（同意/拒绝）
void handle_friend_apply_action_cmd(client_info_p client, cJSON *root, cJSON *response)
{
    // 入参校验
    if (client == NULL || root == NULL || response == NULL)
    {
        printf("错误: handle_friend_apply_action_cmd 输入参数为空\n");
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_PARAM_ERROR);
        cJSON_AddStringToObject(response, "message", "参数错误");
        return;
    }

    // 解析请求参数
    cJSON *req_payload = cJSON_GetObjectItem(root, "payload");
    if (req_payload == NULL)
    {
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_PARAM_ERROR);
        cJSON_AddStringToObject(response, "message", "参数错误");
        return;
    }

    // 提取apply_id（必须为正整数）
    cJSON *apply_id_json = cJSON_GetObjectItem(req_payload, "apply_id");
    if (apply_id_json == NULL || !cJSON_IsNumber(apply_id_json) || apply_id_json->valueint <= 0)
    {
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_PARAM_ERROR);
        cJSON_AddStringToObject(response, "message", "参数错误");
        return;
    }
    int apply_id = apply_id_json->valueint;

    // 提取action（必须是"agree"或"refuse"）
    cJSON *action_json = cJSON_GetObjectItem(req_payload, "action");
    if (action_json == NULL || !cJSON_IsString(action_json) || action_json->valuestring == NULL)
    {
        cJSON_AddStringToObject(response, "type", "friend_apply_action");
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_PARAM_ERROR);
        cJSON_AddStringToObject(response, "message", "参数错误");
        return;
    }
    char action[16] = {0};
    strncpy(action, action_json->valuestring, sizeof(action) - 1);

    // 校验action合法性
    if (strcmp(action, "agree") != 0 && strcmp(action, "refuse") != 0)
    {
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_PARAM_ERROR);
        cJSON_AddStringToObject(response, "message", "参数错误");
        return;
    }

    // 查询申请记录是否存在且未处理
    char check_sql[256] = {0};
    snprintf(check_sql, sizeof(check_sql),
             "SELECT apply_from, apply_to, apply_status FROM friend_apply WHERE id = %d",
             apply_id);

    MYSQL_RES *check_res = NULL;
    if (mysql_query_ex(client->db_conn, check_sql, &check_res) != 0 || check_res == NULL)
    {
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_DB_ERROR);
        cJSON_AddStringToObject(response, "message", "数据库错误");
        mysql_free_result(check_res);
        return;
    }

    // 检查记录是否存在
    MYSQL_ROW check_row = mysql_fetch_row(check_res);
    if (check_row == NULL)
    {
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_NOT_EXIST);
        cJSON_AddStringToObject(response, "message", "申请记录不存在");
        mysql_free_result(check_res);
        return;
    }

    // 解析查询结果
    int apply_from = atoi(check_row[0]);
    int apply_to = atoi(check_row[1]);
    ApplyStatus current_status = (ApplyStatus)atoi(check_row[2]);
    mysql_free_result(check_res);

    // 检查是否已处理
    if (current_status != APPLY_PENDING)
    {
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_ALREADY_HANDLED);
        cJSON_AddStringToObject(response, "message",
                                current_status == APPLY_ACCEPTED ? "该申请已同意" : "该申请已拒绝");
        return;
    }

    // 确定目标状态
    ApplyStatus target_status = (strcmp(action, "agree") == 0) ? APPLY_ACCEPTED : APPLY_REJECTED;

    // 准备当前时间
    char current_time[32] = {0};
    time_t t = time(NULL);
    struct tm *tm = localtime(&t);
    strftime(current_time, sizeof(current_time), "%Y-%m-%d %H:%M:%S", tm);

    // 构建更新SQL
    char update_sql[256] = {0};
    snprintf(update_sql, sizeof(update_sql),
             "UPDATE friend_apply SET apply_status = %d, handle_time = '%s' WHERE id = %d",
             target_status, current_time, apply_id);

    // 执行更新
    if (mysql_query_ex(client->db_conn, update_sql, NULL) != 0)
    {
        cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_DB_ERROR);
        cJSON_AddStringToObject(response, "message", "数据库错误");
        return;
    }

    // 同意时添加双向好友关系 + 在线推送通知
    if (target_status == APPLY_ACCEPTED)
    {
        char add_friend_sql[512] = {0};
        snprintf(add_friend_sql, sizeof(add_friend_sql),
                 "INSERT INTO friend_list (user_id, friend_id) VALUES "
                 "(%d, %d), (%d, %d) "
                 "ON DUPLICATE KEY UPDATE user_id = user_id;",
                 apply_from, apply_to,
                 apply_to, apply_from);

        if (mysql_query_ex(client->db_conn, add_friend_sql, NULL) != 0)
        {
            printf("[错误] 同意申请后插入好友关系失败: %s (SQL: %s)\n",
                   mysql_error(client->db_conn), add_friend_sql);
        }
        else
        {
            printf("[成功] 已添加双向好友关系: %d ↔ %d\n", apply_from, apply_to);

            // 在线检测与通知推送
            int from_connfd = -1;
            int online_ret = query_user_online_connfd(client->db_conn, apply_from, &from_connfd);
            if (online_ret == 0 && from_connfd > 0)
            {
                printf("[通知] 申请人（user_id: %d）在线，connfd: %d，开始构造通知\n",
                       apply_from, from_connfd);

                // 构造通知JSON
                cJSON *notify_json = cJSON_CreateObject();
                if (notify_json == NULL)
                {
                    printf("[错误] 构造好友同意通知JSON失败\n");
                    return;
                }
                cJSON_AddStringToObject(notify_json, "type", "friend_apply_action");
                cJSON_AddNumberToObject(notify_json, "code", FRIEND_APPLY_ALREADY_FRIEND);
                cJSON_AddStringToObject(notify_json, "message", "你的好友申请已被同意");

                // 发送JSON通知
                char *json_str = cJSON_PrintUnformatted(notify_json);
                if (json_str == NULL)
                {
                    printf("[错误] JSON对象转字符串失败\n");
                    return;
                }

                int send_ret = send_message_to_client(from_connfd, json_str);
                if (send_ret >= 0)
                {
                    printf("[成功] 已向申请人（connfd: %d）推送同意通知\n", from_connfd);
                }
                else
                {
                    printf("[错误] 向申请人（connfd: %d）推送通知失败，错误码: %d\n",
                           from_connfd, errno);
                }

                cJSON_Delete(notify_json);
            }
            else if (online_ret == -1)
            {
                printf("[错误] 查询申请人（user_id: %d）在线状态时数据库异常\n", apply_from);
            }
            else
            {
                printf("[通知] 申请人（user_id: %d）当前不在线，无需推送通知\n", apply_from);
            }
        }
    }

    // 处理成功响应
    cJSON_AddNumberToObject(response, "code", FRIEND_APPLY_SUCCESS);
    cJSON_AddStringToObject(response, "message",
                            (target_status == APPLY_ACCEPTED) ? "同意好友申请成功" : "拒绝好友申请成功");
}

// MySQL查询执行函数
static int mysql_query_ex(MYSQL *conn, const char *sql, MYSQL_RES **res)
{
    if (conn == NULL || sql == NULL)
    {
        printf("错误: mysql_query_ex 入参为空\n");
        return -1;
    }

    if (mysql_query(conn, sql) != 0)
    {
        printf("SQL error: %s (SQL: %s)\n", mysql_error(conn), sql);
        return -1;
    }

    if (res != NULL)
    {
        *res = mysql_store_result(conn);
        if (*res == NULL && mysql_field_count(conn) > 0)
        {
            printf("SQL result error: %s (SQL: %s)\n", mysql_error(conn), sql);
            return -1;
        }
    }

    return 0;
}

// 从在线表查询用户的connfd
static int query_user_online_connfd(MYSQL *db_conn, int id, int *out_connfd)
{
    char user_id[32] = {0};
    // 先判断 get_userid_by_userid 是否成功（关键：之前未处理查询失败的情况）
    int get_ret = get_userid_by_userid(db_conn, id, user_id, sizeof(user_id));
    if (get_ret != 0)
    {
        printf("[错误] query_user_online_connfd: 获取 userid 失败（get_ret=%d, user_id=%d）\n",
               get_ret, id);
        return -1; // 获取不到 userid，直接返回失败
    }

    // 字符串 user_id 用 strlen 检查有效性（不能与整数比较）
    if (db_conn == NULL || strlen(user_id) == 0 || out_connfd == NULL)
    {
        printf("[错误] query_user_online_connfd: 入参非法（db_conn=%p, user_id=%s, out_connfd=%p）\n",
               db_conn, user_id, out_connfd);
        return -1;
    }

    *out_connfd = -1;

    // 按 updated_at 降序，获取最新的在线 connfd（解决重复 userid 问题）
    char online_sql[256] = {0};
    snprintf(online_sql, sizeof(online_sql),
             "SELECT connfd FROM online_user WHERE userid = '%s' ORDER BY updated_at DESC LIMIT 1",
             user_id); // 按更新时间倒序，取最新的一条

    MYSQL_RES *online_res = NULL;
    // 检查 mysql_query_ex 结果时，先判断 online_res 是否为 NULL（避免野指针）
    int query_ret = mysql_query_ex(db_conn, online_sql, &online_res);
    if (query_ret != 0)
    {
        printf("[错误] query_user_online_connfd: 执行 SQL 失败（SQL: %s, 错误: %s）\n",
               online_sql, mysql_error(db_conn));
        if (online_res != NULL)
            mysql_free_result(online_res); // 避免内存泄漏
        return -1;
    }
    if (online_res == NULL)
    {
        printf("[错误] query_user_online_connfd: 未获取到结果集（SQL: %s）\n", online_sql);
        return -1;
    }

    //  解析 connfd（确保 online_row[0] 不是 NULL，避免 atoi 转换异常）
    MYSQL_ROW online_row = mysql_fetch_row(online_res);
    if (online_row != NULL && online_row[0] != NULL)
    {
        *out_connfd = atoi(online_row[0]);
        printf("[调试] query_user_online_connfd: 查询到在线 connfd（userid=%s, connfd=%d）\n",
               user_id, *out_connfd);
    }
    else
    {
        printf("[提示] query_user_online_connfd: 未找到在线记录（userid=%s）\n", user_id);
    }

    mysql_free_result(online_res);
    // 正确返回：connfd>0 表示成功，否则返回 -2（未找到在线用户）
    return (*out_connfd > 0) ? 0 : -2;
}
// 通过user_id查询userid
static int get_userid_by_userid(MYSQL *db_conn, int user_id, char *out_userid, size_t out_len)
{
    // 入参合法性校验
    if (db_conn == NULL)
    {
        printf("[错误] get_userid_by_userid: 数据库连接(db_conn)为空\n");
        return -1;
    }
    if (user_id <= 0)
    {
        printf("[错误] get_userid_by_userid: 用户ID(user_id=%d)非法\n", user_id);
        return -1;
    }
    if (out_userid == NULL || out_len <= 1)
    {
        printf("[错误] get_userid_by_userid: 输出缓冲区无效\n");
        return -1;
    }

    // 初始化输出缓冲区
    memset(out_userid, 0, out_len);

    // 构造SQL查询语句
    char sql[256] = {0};
    snprintf(sql, sizeof(sql),
             "SELECT userid FROM `user` WHERE id = %d LIMIT 1",
             user_id);

    // 执行SQL查询
    MYSQL_RES *res = NULL;
    int query_ret = mysql_query_ex(db_conn, sql, &res);
    if (query_ret != 0)
    {
        printf("[错误] get_userid_by_userid: SQL查询失败（user_id=%d）\n", user_id);
        mysql_free_result(res);
        return -2;
    }
    if (res == NULL)
    {
        printf("[错误] get_userid_by_userid: 未获取到查询结果集\n");
        return -2;
    }

    // 解析查询结果
    MYSQL_ROW row = mysql_fetch_row(res);
    if (row == NULL || row[0] == NULL)
    {
        printf("[提示] get_userid_by_userid: 未查询到用户（user_id=%d）\n", user_id);
        mysql_free_result(res);
        return -3;
    }

    // 提取userid并填充到输出缓冲区
    const char *db_userid = row[0];
    size_t db_userid_len = strlen(db_userid);
    if (db_userid_len >= out_len)
    {
        printf("[警告] get_userid_by_userid: 输出缓冲区不足，将截断存储\n");
        db_userid_len = out_len - 1;
    }
    strncpy(out_userid, db_userid, db_userid_len);
    out_userid[db_userid_len] = '\0';

    // 释放资源
    mysql_free_result(res);

    printf("[成功] get_userid_by_userid: 查询完成（user_id=%d → userid=%s）\n",
           user_id, out_userid);

    return 0;
}
